// Package mgmt
// @Author: zhengqi Wu
// @Description:
// @Version: 1.0.0
// @Date: 2021/4/19 22:23 上午
// @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
//


const encoding = require("../encoding");
const buffer2arraybuffer = require("../common/buffer2arraybuffer");
const {createIdentifierByComponents} = require("../component/Identifier");
const {createNackByMINPacket} = require("../packet/Nack");
const {createDataByMinPacket} = require("../packet/Data");
const {getNackReasonString} = require("../component/NackHeader");
const {isNack} = require("../packet/PacketTypeHelper");
const {isData} = require("../packet/PacketTypeHelper");
const {ControlResponseCodeContinue} = require("./ControlResponse");
const {ControlResponseCodeCommonError} = require("./ControlResponse");
const {ControlResponseCodeSuccess} = require("./ControlResponse");
const {ControlResponse} = require("./ControlResponse");
const {createIdentifierByString} = require("../component/Identifier");
const {Interest} = require("../packet/Interest");
const defaultInterestLifeTime = 4000 // 默认兴趣包生存期
/**
 * @description
 * 1. 默认TTL为1，表示当前管理命令只能传递给一跳路由器，即只能做本地管理用
 * 2. 如果想通过控制管理命令做远程管理，需要显示设置这个值，将其设置为一个较大值，这样才能将命令兴趣包转发到多跳路由器上
 * @type {number}
 */
const defaultTTL = 1 // 默认TTL

/**
 * @description CommandExecutor 表示一个命令执行器
 */
class CommandExecutor{
    //////////////Getters & Setters/////////////////////
    ////////////////////////////////////////////////////
    set keyChain(value){
        this._keyChain = value
    }

    get keyChain(){
        return this._keyChain
    }
    get autoShutdown() {
        return this._autoShutdown;
    }

    set autoShutdown(value) {
        this._autoShutdown = value;
    }

    get command() {
        return this._command;
    }

    set command(value) {
        this._command = value;
    }

    get interestLifeTime() {
        return this._interestLifeTime;
    }

    set interestLifeTime(value) {
        this._interestLifeTime = value;
    }

    get ttl() {
        return this._ttl;
    }

    set ttl(value) {
        this._ttl = value;
    }

    get logicFace() {
        return this._logicFace;
    }

    set logicFace(value) {
        this._logicFace = value;
    }
    constructor() {
        /**
         * 用于给通信包签名（如果没有设置则不执行包签名）
         * @type {null}
         * @private
         */
        this._keyChain = null;
        /**
         * 要执行的命令
         * @type {IControlCommand}
         */
        this._command = null
        /**
         * 命令兴趣包的生存期
         * @type {bigint}
         */
        this._interestLifeTime = BigInt(0)
        /**
         * 命令兴趣包的 TTL
         * @type {bigint}
         */
        this._ttl = BigInt(0)
        /**
         * ICN 逻辑接口，用于和路由器进行ICN通信
         * @type {LogicFace}
         */
        this._logicFace = null
        /**
         * autoShutdown 表示命令执行器是否在命令执行完成后自动关闭
         * @type {boolean}
         */
        this._autoShutdown = false
    }

    /**
     * @description Init 初始化命令执行器
     * @param command
     * @param logicFace
     */
    init(command, logicFace){
        this._command = command
        this._interest = BigInt(defaultInterestLifeTime)
        this._ttl = BigInt(defaultTTL)
        this._logicFace = logicFace
        this._autoShutdown = false
        this._keyChain = null
    }

    /**
     * @description newCommandInterest 根据请求命令构造对应的命令兴趣包
     */
    newCommandInterest(){
        let interest = new Interest()
        let identifier = createIdentifierByString(buildPrefix(this._command))
        interest.setName(identifier)
        interest.TTL.setTTL(this._ttl)
        interest.InterestLifeTime.setInterestLifeTime(this._interest)
        interest.IsCommandInterest = true
        if (this._keyChain !== null)
            this._keyChain.SignInterest(interest)
        return interest
    }

    /**
     * 开始执行命令
     * @return {ControlResponse}
     */
    start(){
        // 构造管理命令前缀
        let commandInterest = this.newCommandInterest()
        let controlResponse = new ControlResponse()
        try{
            // 如果存在管理命令参数，则将其添加到命令兴趣包的名字当中
            if(this._command.getParameters() !== undefined)
                commandInterest.appendCommandParameters(this._command.getParameters())

            // 发送第一个命令兴趣包
            this._logicFace.SendInterest(commandInterest)
            // 等待兴趣包应答
            let minPacket = this._logicFace.ReceivePacket()

            // TODO 处理EOF
            // 判断收到的是什么包
            // 根据收到的包的类型分别处理
            if(isData(minPacket)){
                // onData
                let data = createDataByMinPacket(minPacket)
                return this.onReceiveFirstMetaData(data)
            }

            if(isNack(minPacket)){
                // onNack
                let nack = createNackByMINPacket(minPacket)
                controlResponse.code = ControlResponseCodeCommonError
                controlResponse.msg = `Request failed, receive nack => ${getNackReasonString(nack.getNackReason())}`
            }else{
                // 收到其他类型的包直接抛出错误，未预期的行为
                controlResponse.code = ControlResponseCodeCommonError
                controlResponse.msg = "Receive one other type packet, Unexpected behavior!"
            }

            // 如果设置了自动shutdown，则执行shutdown
            if(this._autoShutdown){
                this.shutdown()
            }
            return controlResponse
        }catch (e) {
            throw e
        }
    }

    shutdown(){
        // Shutdown 命令请求结束之后，如果想要关闭使用的 LogicFace，需要调用本函数关闭LogicFace
        this._logicFace.Shutdown()
    }

    onReceiveFirstMetaData(data){
        try{
            let controlResponse = new ControlResponse()
            controlResponse.unmarshalJSON(data.getValue())

            switch (controlResponse.code) { // number
                case ControlResponseCodeSuccess:
                    // 请求成功，直接返回结果
                    return controlResponse
                case ControlResponseCodeCommonError:
                    // 请求失败，直接返回结果，结果中已经包含错误信息
                    return controlResponse
                case ControlResponseCodeContinue:
                    // 请求到元数据，继续请求所有的分片
                    let metaData = controlResponse.getMeta()
                    let length = Number(metaData.sliceNum)

                    let valueBuf = [] // 用于收集所有收到的Payload
                    for (let i = 0; i < length; i++) {
                        // 构建兴趣包
                        let tempInterest = this.newCommandInterest()
                        // let tempIdentifier = tempInterest.getName()
                        let tempIdentifier = createIdentifierByComponents(data.getName().getComponents())
                        tempIdentifier.appendVersionNumber(Number(metaData.version))
                        tempIdentifier.appendFragmentNumber(i)
                        tempInterest.setName(tempIdentifier)
                        tempInterest.TTL.setTTL(this._ttl)
                        tempInterest.InterestLifeTime.setInterestLifeTime(this._interest)
                        // 发送兴趣包
                        try {
                            this._logicFace.SendInterest(tempInterest)
                        } catch (e) {
                            // 错误处理
                            controlResponse.code = ControlResponseCodeCommonError
                            controlResponse.msg = "Send Interest failed"
                            return controlResponse
                        }
                        // 等待接收新分片
                        try {
                            let res = this._logicFace.ReceivePacket()
                            if (isData(res)) {
                                let payLoadBlock = res.ReadOnlyField.getBlockByType(encoding.tlv.ComponentType.TlvPayload)
                                let value = payLoadBlock.getValue()
                                valueBuf.push(value)
                            } else {
                                // 收到的不是Data包，未预期行为
                                controlResponse.Code = ControlResponseCodeCommonError
                                controlResponse.msg = "Receive other packet（not Data），Unexpected behavior！"
                                return controlResponse
                            }
                        } catch (e) {
                            // 错误处理
                            controlResponse.code = ControlResponseCodeCommonError
                            controlResponse.msg = "Request timeout!"
                            return controlResponse
                        }

                        // 得到返回数据
                        let bytes = buffer2arraybuffer(Buffer.concat(valueBuf))
                        controlResponse.setBytes(bytes)
                        controlResponse.code = ControlResponseCodeSuccess
                        controlResponse.msg = ""
                        // 关闭逻辑接口
                    }
                    return controlResponse
            }
        }catch (e) {
            throw e
        }
    }
}

// buildPrefix 构造命令兴趣包请求前缀
//
// @Description:
// @param moduleName
// @param action
// @return string
//
function buildPrefix(command) {
    return command.getTopPrefix() + "/" + command.getModuleName() + "/" + command.getAction()
}

module.exports = {
    CommandExecutor: CommandExecutor
}